#include <Python.h>
#include <stdint.h>
#include "hir_instructions.hpp"

namespace hir
{
Instruction::Instruction() : graphId_(-1),bci_(-1) {}
Instruction::~Instruction() {}

#define DEFINE_COMMON_METH(x)\
    const char * x::name() const \
    {\
        return #x;\
    }\
    uint32_t x::id() const\
    {\
        return x##_id; \
    }
H_INSTR_LIST(DEFINE_COMMON_METH);

Const::Const(PyObject * object) : object_(object) {}

MakeFunc::MakeFunc(uint32_t codeOperand,uint32_t * defaultAugs,uint32_t defaultAugsCount)
{
    operandList_.push_back(codeOperand);
    for(int i = 0; i < defaultAugsCount; ++i)
    {
        operandList_.push_back(defaultAugs[i]);
    }
}
MakeClosure::MakeClosure(uint32_t codeOperand,uint32_t closureOperand,uint32_t * defaultAugs,uint32_t defaultAugsCount)
{
    operandList_.push_back(codeOperand);
    operandList_.push_back(closureOperand);
    for(int i = 0; i < defaultAugsCount; ++i)
    {
        operandList_.push_back(defaultAugs[i]);
    }
}
#define DEFINE_UNARY_INSTRUCTION(x) \
    Unary##x::Unary##x(uint32_t operand) { \
        operandList_.push_back(operand); \
    }
#define DEFINE_BINARY_INSTRUCTION(x) \
    Binary##x::Binary##x(uint32_t operand1,uint32_t operand2) {\
        operandList_.push_back(operand1);\
        operandList_.push_back(operand2);\
    }
#define DEFINE_ONE_OPERAND_INSTRUCTION(x) \
    x::x(uint32_t operand) { \
        operandList_.push_back(operand); \
    }

#define DEFINE_TWO_OPERAND_INSTRUCTION(x) \
    x::x(uint32_t operand1,uint32_t operand2) {\
        operandList_.push_back(operand1);\
        operandList_.push_back(operand2);\
    }
#define DEFINE_THREE_OPERAND_INSTRUCTION(x) \
    x::x(uint32_t operand1,uint32_t operand2,uint32_t operand3) {\
        operandList_.push_back(operand1);\
        operandList_.push_back(operand2);\
        operandList_.push_back(operand3);\
    }

#define DEFINE_FOUR_OPERAND_INSTRUCTION(x) \
    x::x(uint32_t operand1,uint32_t operand2,uint32_t operand3,uint32_t operand4) {\
        operandList_.push_back(operand1);\
        operandList_.push_back(operand2);\
        operandList_.push_back(operand3);\
        operandList_.push_back(operand4);\
    }


DEFINE_UNARY_INSTRUCTION(Positive);
DEFINE_UNARY_INSTRUCTION(Negative);
DEFINE_UNARY_INSTRUCTION(Not);
DEFINE_UNARY_INSTRUCTION(Convert);
DEFINE_UNARY_INSTRUCTION(Invert);
DEFINE_BINARY_INSTRUCTION(Power)
DEFINE_BINARY_INSTRUCTION(Multiply);
DEFINE_BINARY_INSTRUCTION(Divide);
DEFINE_BINARY_INSTRUCTION(Modulo);
DEFINE_BINARY_INSTRUCTION(Add);
DEFINE_BINARY_INSTRUCTION(Subtract);
DEFINE_BINARY_INSTRUCTION(Subscr);
DEFINE_BINARY_INSTRUCTION(Floor_divide);
DEFINE_BINARY_INSTRUCTION(True_divide);
DEFINE_BINARY_INSTRUCTION(Lshift);
DEFINE_BINARY_INSTRUCTION(Rshift);
DEFINE_BINARY_INSTRUCTION(And);
DEFINE_BINARY_INSTRUCTION(Xor);
DEFINE_BINARY_INSTRUCTION(Or);
DEFINE_THREE_OPERAND_INSTRUCTION(Slice);
DEFINE_FOUR_OPERAND_INSTRUCTION(StoreSlice);
DEFINE_THREE_OPERAND_INSTRUCTION(DeleteSlice);
DEFINE_THREE_OPERAND_INSTRUCTION(BuildSlice);
LoadConst::LoadConst(uint32_t oparg) : oparg_(oparg) {}
LoadName::LoadName(uint32_t oparg) : oparg_(oparg) {}

LoadAttr::LoadAttr(uint32_t objectOperand,uint32_t oparg) : oparg_(oparg)
{
    operandList_.push_back(objectOperand);
}

LoadGlobal::LoadGlobal(uint32_t oparg) : oparg_(oparg) {}
LoadFast::LoadFast(uint32_t oparg) : oparg_(oparg) {}
LoadClosure::LoadClosure(uint32_t oparg) : oparg_(oparg) {}
LoadDeref::LoadDeref(uint32_t oparg) : oparg_(oparg) {}
DEFINE_THREE_OPERAND_INSTRUCTION(StoreMap);
DEFINE_THREE_OPERAND_INSTRUCTION(StoreSubscr);
StoreName::StoreName(uint32_t valueOperand,uint32_t oparg) : oparg_(oparg)
{
    operandList_.push_back(valueOperand);
}

StoreAttr::StoreAttr(uint32_t objectOperand,uint32_t valueOperand,uint32_t oparg) : oparg_(oparg)
{
    operandList_.push_back(objectOperand);
    operandList_.push_back(valueOperand);
}

StoreGlobal::StoreGlobal(uint32_t valueOperand,uint32_t oparg) : oparg_(oparg)
{
    operandList_.push_back(valueOperand);
}

StoreFast::StoreFast(uint32_t objectOperand,uint32_t oparg) : oparg_(oparg)
{
    operandList_.push_back(objectOperand);
}

StoreDeref::StoreDeref(uint32_t objectOperand,uint32_t oparg) : oparg_(oparg)
{
    operandList_.push_back(objectOperand);
}
DEFINE_TWO_OPERAND_INSTRUCTION(DeleteSubscr);
DEFINE_ONE_OPERAND_INSTRUCTION(DeleteName);

DeleteAttr::DeleteAttr(uint32_t objectOperand,uint32_t oparg) : oparg_(oparg)
{
    operandList_.push_back(objectOperand);
}

DeleteFast::DeleteFast(uint32_t oparg) : oparg_(oparg)
{
}
DeleteGlobal::DeleteGlobal(uint32_t oparg) : oparg_(oparg)
{
}
DEFINE_ONE_OPERAND_INSTRUCTION(GetIter);
DEFINE_ONE_OPERAND_INSTRUCTION(PrintExpr);
DEFINE_ONE_OPERAND_INSTRUCTION(PrintItem);
DEFINE_TWO_OPERAND_INSTRUCTION(PrintItemTo);
DEFINE_ONE_OPERAND_INSTRUCTION(PrintNewLineTo);
DEFINE_ONE_OPERAND_INSTRUCTION(ReturnValue);
DEFINE_ONE_OPERAND_INSTRUCTION(YieldValue);
JumpForward::JumpForward(uint32_t label) : JumpInstruction(label) {}

JumpIfFalse::JumpIfFalse(uint32_t objectOperand,uint32_t label) : JumpInstruction(label)
{
    operandList_.push_back(objectOperand);
}

JumpIfTrue::JumpIfTrue(uint32_t objectOperand,uint32_t label) : JumpInstruction(label)
{
    operandList_.push_back(objectOperand);
}

ForIter::ForIter(uint32_t objectOperand,uint32_t label) : JumpInstruction(label)
{
    operandList_.push_back(objectOperand);
}

ContinueLoop::ContinueLoop(uint32_t label) : JumpInstruction(label) {}
DEFINE_ONE_OPERAND_INSTRUCTION(ImportStar);
DEFINE_THREE_OPERAND_INSTRUCTION(ExecStatement);

UnpackSequence::UnpackSequence(uint32_t operand,uint32_t index) : index_(index)
{
    operandList_.push_back(operand);

}

DEFINE_TWO_OPERAND_INSTRUCTION(ListAppend);

BuildMap::BuildMap(uint32_t preservedSize) : preservedSize_(preservedSize)
{
}
DEFINE_THREE_OPERAND_INSTRUCTION(BuildClass);

CmpStatement::CmpStatement(uint32_t objectOperand1,uint32_t objectOperand2, uint32_t type) : type_(type)
{
    operandList_.push_back(objectOperand1);
    operandList_.push_back(objectOperand2);
}

ImportName::ImportName(uint32_t operand1,uint32_t operand2,uint32_t oparg) : oparg_(oparg)
{
    operandList_.push_back(operand1);
    operandList_.push_back(operand2);
}

ImportFrom::ImportFrom(uint32_t moduleOperand,uint32_t oparg) : oparg_(oparg)
{
    operandList_.push_back(moduleOperand);
}

DEFINE_THREE_OPERAND_INSTRUCTION(RaiseStatment);
DEFINE_TWO_OPERAND_INSTRUCTION(SetAdd);
DEFINE_THREE_OPERAND_INSTRUCTION(MapAdd);
DEFINE_THREE_OPERAND_INSTRUCTION(WithCleanup);
CallFunction::CallFunction(uint32_t argumentCount) : argumentCount_(argumentCount)
{
}

JumpInstruction::JumpInstruction(uint32_t label) : label_(label) {}

Phi::Phi(uint32_t index) : index_(index) {}

#define DEFINE_INPLACE_INSTRUCTION(x) \
    Inplace##x::Inplace##x(uint32_t operand1,uint32_t operand2) {\
        operandList_.push_back(operand1);\
        operandList_.push_back(operand2);\
    }

DEFINE_INPLACE_INSTRUCTION(Add);
DEFINE_INPLACE_INSTRUCTION(Subtract);
DEFINE_INPLACE_INSTRUCTION(Multiply);
DEFINE_INPLACE_INSTRUCTION(Divide);
DEFINE_INPLACE_INSTRUCTION(Modulo);
DEFINE_INPLACE_INSTRUCTION(Power);
DEFINE_INPLACE_INSTRUCTION(Lshift);
DEFINE_INPLACE_INSTRUCTION(Rshift);
DEFINE_INPLACE_INSTRUCTION(And);
DEFINE_INPLACE_INSTRUCTION(Xor);
DEFINE_INPLACE_INSTRUCTION(Or);
DEFINE_INPLACE_INSTRUCTION(TrueDivide);
DEFINE_INPLACE_INSTRUCTION(FloorDivide);
}

